package com.inspur.edp.bef.bemanager.generatecomponent;

import com.inspur.edp.bef.bemanager.generatecomponent.componentgenerators.BaseComponentGenerator;
import com.inspur.edp.bef.bemanager.generatecomponent.componentgenerators.BeComponentGenerator;
import com.inspur.edp.bef.bemanager.generatecomponent.componentgenerators.BeMgrComponentGenerator;
import com.inspur.edp.bef.bemanager.generatecomponent.componentgenerators.DeterminationComponentGenerator;
import com.inspur.edp.bef.bemanager.generatecomponent.componentgenerators.TccActionComponentGenerator;
import com.inspur.edp.bef.bemanager.generatecomponent.componentgenerators.ValidationComponentGenerator;
import com.inspur.edp.bef.bemanager.util.DataValidatorUtil;
import com.inspur.edp.bef.bizentity.GspBizEntityObject;
import com.inspur.edp.bef.bizentity.GspBusinessEntity;
import com.inspur.edp.bef.bizentity.common.BizEntityJsonConst;
import com.inspur.edp.bef.bizentity.common.OperationConvertUtils;
import com.inspur.edp.bef.bizentity.operation.*;
import com.inspur.edp.bef.bizentity.operation.collection.DeterminationCollection;
import com.inspur.edp.bef.bizentity.operation.collection.ValidationCollection;
import com.inspur.edp.bef.bizentity.operation.internalmgraction.TccSettingElement;
import com.inspur.edp.cef.designtime.api.collection.CommonDtmCollection;
import com.inspur.edp.cef.designtime.api.collection.CommonValCollection;
import com.inspur.edp.cef.designtime.api.json.CefNames;
import com.inspur.edp.cef.designtime.api.operation.CommonDetermination;
import com.inspur.edp.cef.designtime.api.operation.CommonValidation;
import com.inspur.edp.cef.variable.dtgenerator.vardtmGenerate.cmpgenerators.CommonDtmGenerator;
import com.inspur.edp.das.commonmodel.IGspCommonObject;
import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import lombok.Getter;
import lombok.var;

import java.util.ArrayList;

public class ComponentGenerator {


    public static ComponentGenerator getInstance() {
        return new ComponentGenerator();
    }

    private ComponentGenerator() {
        this.createComponentActionList=new ArrayList<>();
    }

    @Getter
    private boolean anyGenerated;
    /**
     * 用来记录已生成构件的编号
     */
    private ArrayList<String> createComponentActionList;
    /**
     * BE的编号
     */
    private String privateBizEntityCode;

    private String getBizEntityCode() {
        return privateBizEntityCode;
    }

    private void setBizEntityCode(String value) {
        privateBizEntityCode = value;
    }

    /**
     * BE的程序集名称
     */
    private String privateAssemblyName;

    private String getAssemblyName() {
        return privateAssemblyName;
    }

    private void setAssemblyName(String value) {
        privateAssemblyName = value;
    }

    private String privateNameSpace;

    private String getNameSpace() {
        return privateNameSpace;
    }

    private void setNameSpace(String value) {
        privateNameSpace = value;
    }

    /**
     * 是否子节点
     */
    private boolean privateIsChildObj;

    private boolean getIsChildObj() {
        return privateIsChildObj;
    }

    private void setIsChildObj(boolean value) {
        privateIsChildObj = value;
    }

    /**
     * 当前节点编号
     */
    private String privateObjCode;

    private String getObjCode() {
        return privateObjCode;
    }

    private void setObjCode(String value) {
        privateObjCode = value;
    }

    /**
     * 业务对象ID
     */
    private String privateBizObjectID;

    private String getBizObjectID() {
        return privateBizObjectID;
    }

    private void setBizObjectID(String value) {
        privateBizObjectID = value;
    }

    /**
     * BE变量实体的编号
     */
    private String privateBEVariableEntityCode;

    private String getBEVariableEntityCode() {
        return privateBEVariableEntityCode;
    }

    private void setBEVariableEntityCode(String value) {
        privateBEVariableEntityCode = value;
    }

    private GspMetadata metadata;

    /**
     * 入口：支持Be设计器生成构件元数据
     *
     * @param metadata BE实体
     * @param bePath   be路径
     */
    public ArrayList<String> generateComponent(GspMetadata metadata, String bePath) {
        GspBusinessEntity bizEntity = (GspBusinessEntity) ((metadata.getContent() instanceof GspBusinessEntity) ? metadata.getContent() : null);
        String bizObjectID = metadata.getHeader().getBizobjectID();
        // 参数校验
        DataValidatorUtil.CheckForNullReference(bizEntity, "bizEntity");
        DataValidatorUtil.CheckForEmptyString(bePath, "path");
        setAssemblyName(ComponentGenUtil.getComponentAssemblyName(bePath));
        setNameSpace(ComponentGenUtil.getComponentProjInfo(bePath).getNameSpace());
        DataValidatorUtil.CheckForEmptyString(getAssemblyName(), "AssemblyName");
        setBizEntityCode(bizEntity.getCode());
        DataValidatorUtil.CheckForEmptyString(getBizEntityCode(), "BizEntityCode");
        setBizObjectID(bizObjectID);
        this.metadata = metadata;
        String path = ComponentGenUtil.PrepareComponentDir(bePath);
        generateBEMgrComponents(bizEntity, path);
        // 获取根节点
        GspBizEntityObject mainObj = bizEntity.getMainObject();
        generateMainObjComponent(mainObj, path, metadata);
        for (IGspCommonObject childObj : mainObj.getContainChildObjects()) {
            generateChildObjComponent((GspBizEntityObject) childObj, path,metadata);
        }
        generateVariableDtmComponents(bizEntity, path);
        return this.createComponentActionList;
    }

    /**
     * 变量联动计算
     *
     * @param viewModel
     * @param
     */
    private void generateVariableDtmComponents(GspBusinessEntity viewModel, String path) {
        if (viewModel.getVariables() == null) {
            return;
        }

        var cdtDef = viewModel.getVariables();
        setBEVariableEntityCode(viewModel.getVariables().getCode());
        for (CommonDetermination dtmInfo : cdtDef.getDtmBeforeSave()) {
            if (dtmInfo.getIsRef() || !dtmInfo.getIsGenerateComponent()) {
                continue;
            }
            setNewCompActionCode(CommonDtmGenerator.getInstance().GenerateComponent(viewModel, dtmInfo, path, this.getBEVariableEntityCode(), this.getAssemblyName(), getNameSpace(), this.getBizObjectID()));
        }
        for (CommonDetermination dtmInfo : cdtDef.getDtmAfterCreate()) {
            if (dtmInfo.getIsRef() || !dtmInfo.getIsGenerateComponent()) {
                continue;
            }
            setNewCompActionCode(CommonDtmGenerator.getInstance().GenerateComponent(viewModel, dtmInfo, path, this.getBEVariableEntityCode(), this.getAssemblyName(), getNameSpace(), this.getBizObjectID()));
        }
        for (CommonDetermination dtmInfo : cdtDef.getDtmAfterModify()) {
            if (dtmInfo.getIsRef() || !dtmInfo.getIsGenerateComponent()) {
                continue;
            }
            setNewCompActionCode(CommonDtmGenerator.getInstance().GenerateComponent(viewModel, dtmInfo, path, this.getBEVariableEntityCode(), this.getAssemblyName(), getNameSpace(), this.getBizObjectID()));
        }
    }

    /**
     * &#x751f;&#x6210;BEMgr&#x6784;&#x4ef6;
     *
     * @param bizEntity BE&#x5b9e;&#x4f53;
     * @param path      &#x751f;&#x6210;&#x8def;&#x5f84;
     * @param
     */
    private void generateBEMgrComponents(GspBusinessEntity bizEntity, String path) {
        setIsChildObj(false);
        for (BizOperation bizMgrAction : bizEntity.getCustomMgrActions()) {
            if (bizMgrAction.getIsRef() || !bizMgrAction.getIsGenerateComponent()) {
                continue;
            }
            setNewCompActionCode(BeMgrComponentGenerator.getInstance().generateComponent(bizMgrAction, path, this.getBizEntityCode(), this.getAssemblyName(), this.getIsChildObj(), bizEntity.getCode(), this.getBizObjectID(), metadata, getNameSpace()));
        }
    }

    /**
     * 生成BE主对象中动作对应的构件
     *
     * @param mainObj
     * @param path
     */
    private void generateMainObjComponent(GspBizEntityObject mainObj, String path, GspMetadata metadata) {
        setIsChildObj(false);
        generateObjectComponent(mainObj, path ,metadata);
    }

    private void generateObjectComponent(GspBizEntityObject obj, String path, GspMetadata metadata) {
        generateBEComponents(obj, path);
        generateDeterminationComponents(obj, path);
        generateValidationComponents(obj, path);
        generateTccActionComponents(obj, path, metadata);
    }

    /**
     * 生成BE子对象中动作对应的构件
     *
     * @param childObj
     * @param path
     */
    private void generateChildObjComponent(GspBizEntityObject childObj, String path,GspMetadata metadata) {
        setIsChildObj(true);
        this.setObjCode(childObj.getCode());
        generateObjectComponent(childObj, path, metadata);
        //递归当前子对象的子对象
        if (childObj.getContainChildObjects().size() > 0) {
            for (IGspCommonObject obj : childObj.getContainChildObjects()) {
                generateChildObjComponent((GspBizEntityObject) obj, path, metadata);
            }
        }
    }

    private void generateBEComponents(GspBizEntityObject obj, String path) {
        for (BizOperation bizAction : obj.getCustomBEActions()) {
            if (bizAction.getIsRef() || !bizAction.getIsGenerateComponent()) {
                continue;
            }
            String code = null;
            if (obj.getIsRootNode()) {
                code = obj.getCode();
            } else {
                code = this.getObjCode();
            }
            setNewCompActionCode(BeComponentGenerator.getInstance().generateComponent(bizAction,
                path, this.getBizEntityCode(), this.getAssemblyName(), this.getIsChildObj(), code,
                this.getBizObjectID(), metadata, getNameSpace()));
        }
    }

    private void generateDeterminationComponents(GspBizEntityObject obj, String path) {
        DeterminationCollection determinations = obj.getDeterminations();
        for (BizOperation determination : determinations) {
            if (determination.getIsRef() || !determination.getIsGenerateComponent()) {
                continue;
            }
            String code = obj.getIsRootNode() ? obj.getCode() : this.getObjCode();
            setNewCompActionCode(DeterminationComponentGenerator.getInstance().generateComponent(determination, path, this.getBizEntityCode(), this.getAssemblyName(), this.getIsChildObj(), code, this.getBizObjectID(), metadata, getNameSpace()));
        }
        generateCommonDtm(obj, path, obj.getDtmAfterCreate(), CefNames.DtmAfterCreate);
        generateCommonDtm(obj, path, obj.getAllDtmAfterModify(), CefNames.DtmAfterModify);
        generateCommonDtm(obj, path, obj.getAllDtmBeforeSave(), CefNames.DtmBeforeSave);
        generateCommonDtm(obj, path, obj.getDtmBeforeQuery(), BizEntityJsonConst.B4QueryDtm);
        generateCommonDtm(obj, path, obj.getDtmAfterQuery(), BizEntityJsonConst.AftQueryDtm);
        generateCommonDtm(obj, path, obj.getDtmCancel(), BizEntityJsonConst.DtmCancel);
        generateCommonDtm(obj, path, obj.getDtmBeforeRetrieve(), BizEntityJsonConst.B4RetrieveDtm);
        generateCommonDtm(obj, path, obj.getDtmAfterLoading(), BizEntityJsonConst.AftLoadingDtm);
    }

    private void generateCommonDtm(GspBizEntityObject obj, String path,
      CommonDtmCollection dtmCollection, String commonDtmType) {
        if (dtmCollection == null) {
            return;
        }
        for(CommonDetermination dtm : dtmCollection) {
          if (dtm.getIsRef() || !dtm.getIsGenerateComponent()
              || obj.getDeterminations().findById(dtm.getID())!=null) {
              continue;
          }
          Determination determination = OperationConvertUtils.convertToDtm(dtm, commonDtmType, obj);
          String code = obj.getIsRootNode() ? obj.getCode() : this.getObjCode();
          setNewCompActionCode(DeterminationComponentGenerator.getInstance().generateComponent(
              determination, path, this.getBizEntityCode(), this.getAssemblyName(),
              this.getIsChildObj(), code, this.getBizObjectID(), metadata, getNameSpace()));
          dtm.setComponentId(determination.getComponentId());
          dtm.setComponentName(determination.getComponentName());
          dtm.setComponentPkgName(determination.getComponentPkgName());
        }
    }

    private void generateValidationComponents(GspBizEntityObject obj, String path) {
        ValidationCollection validations = obj.getValidations();
        for (BizOperation validation : validations) {
            if (validation.getIsRef() || !validation.getIsGenerateComponent()) {
                continue;
            }
            String code = obj.getIsRootNode() ? obj.getCode() : this.getObjCode();
            setNewCompActionCode(ValidationComponentGenerator.getInstance().generateComponent(validation, path, this.getBizEntityCode(), this.getAssemblyName(), this.getIsChildObj(), code, this.getBizObjectID(), metadata, getNameSpace()));
        }
        generateCommonVal(obj, path, obj.getValAfterSave(), BizEntityJsonConst.ValidationAfterSave);
        generateCommonVal(obj, path, obj.getallValBeforeSave(), CefNames.ValBeforeSave);
        generateCommonVal(obj, path, obj.getAllValAfterModify(), CefNames.ValAfterModify);
    }

    private void generateCommonVal(GspBizEntityObject obj, String path,
        CommonValCollection collection, String commonType) {
        if (collection == null) {
            return;
        }
        for(CommonValidation item : collection) {
            if (item.getIsRef() || !item.getIsGenerateComponent()
                || obj.getValidations().findById(item.getID())!=null) {
                continue;
            }
            Validation validation = OperationConvertUtils.convertToVal(item, commonType, obj);
            String code = obj.getIsRootNode() ? obj.getCode() : this.getObjCode();
            setNewCompActionCode(ValidationComponentGenerator.getInstance().generateComponent(
                validation, path, this.getBizEntityCode(), this.getAssemblyName(),
                this.getIsChildObj(), code, this.getBizObjectID(), metadata, getNameSpace()));
            item.setComponentId(validation.getComponentId());
            item.setComponentName(validation.getComponentName());
            item.setComponentPkgName(validation.getComponentPkgName());
        }
    }

    private void generateTccActionComponents(GspBizEntityObject obj, String path, GspMetadata metadata) {

        for (TccSettingElement ele: obj.getTccSettings()) {
            TccAction action = ele.getTccAction();
            if (action.getIsRef() || !action.getIsGenerateComponent()) {
                continue;
            }
            String code = null;
            if (obj.getIsRootNode()) {
                code = obj.getCode();
            } else {
                code = this.getObjCode();
            }
            setNewCompActionCode(TccActionComponentGenerator.getInstance().generateComponent(ele, path, metadata, code));
        }
    }

    private void setNewCompActionCode(String code) {
        anyGenerated = true;
        if (code == null || code.equals("")) {
            return;
        }
        this.createComponentActionList.add(code);
    }

    public GspMetadata createCompByOperation(BizOperation operation, String bePath,
        String bizEntityCode, boolean isChildObj, String objCode, String bizObjectID ) {
        String path = ComponentGenUtil.PrepareComponentDir(bePath);
        String assemblyName = ComponentGenUtil.getComponentAssemblyName(bePath);
        String defaultNameSpace = ComponentGenUtil.getComponentProjInfo(bePath).getNameSpace();
        BaseComponentGenerator generator = ComponentGeneratorFactory.getInstance().getGenerator(
            operation.getOpType());
        return generator.createComponent(operation, path, bizEntityCode, assemblyName, isChildObj,
            objCode, bizObjectID, defaultNameSpace);
    }

    public GspMetadata createCompByVarDtm(CommonDetermination dtm, GspBusinessEntity be, String path,
        String bizObjectId) {
        String assemblyName = ComponentGenUtil.getComponentAssemblyName(path);
        String nameSpace = ComponentGenUtil.getComponentProjInfo(path).getNameSpace();

        return CommonDtmGenerator.getInstance().createComponent(be, dtm, path, be.getVariables().getCode(),
            assemblyName, nameSpace, bizObjectId);
    }
}
